/*
 */
package org.hook.showcase.concurrent.tools;

import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author suwuqiang 2011-12-19
 */
public class SemaphoreCase<T> {
	private final int capacity;
	private final ObjectFactory<T> factory;
	private final Lock lock = new ReentrantLock();
	private final Semaphore semaphore;
	private Node head;
	private Node tail;

	public SemaphoreCase(final int capacity, final ObjectFactory<T> factory) {
		this.capacity = capacity;
		this.factory = factory;
		this.semaphore = new Semaphore(this.capacity);
		this.head = null;
		this.tail = null;
	}

	public T getObject() throws InterruptedException {
		semaphore.acquire();
		return getNextObject();
	}

	public void returnObject(T t) {
		returnObjectToPool(t);
		semaphore.release();
	}

	private T getNextObject() {
		lock.lock();
		try {
			if (head == null) {
				return factory.makeObject();
			} else {
				Node ret = head;
				head = head.next;
				if (head == null)
					tail = null;
				ret.next = null;// help GC
				return ret.obj;
			}
		} finally {
			lock.unlock();
		}
	}

	private void returnObjectToPool(T t) {
		lock.lock();
		try {
			Node node = new Node();
			node.obj = t;
			if (tail == null) {
				head = tail = node;
			} else {
				tail.next = node;
				tail = node;
			}

		} finally {
			lock.unlock();
		}
	}

	public interface ObjectFactory<T> {
		T makeObject();
	}

	class Node {
		T obj;
		Node next;
	}

}
